/*
 Copyright 2013--Present JMM_PROGNAME
 
 This file is distributed under the terms of the JMM_PROGNAME License.
 
 You should have received a copy of the JMM_PROGNAME License.
 If not, see <JMM_PROGNAME WEBSITE>.
*/
// CREATED    : 7/16/2015
// LAST UPDATE: 10/1/2015

#include "statsxx/optimization/line_search_methods/LineSearchMethod.hpp"

// STL
#include <functional> // std::function<>, std::bind(), std::placeholders
#include <tuple>      // std::tuple<>, std::make_tuple()

// jScience
#include "jScience/linalg/Vector.hpp" // Vector<>

// stats++
#include "statsxx/optimization/bracket_methods/Brent.hpp" // Brent::minimize()


static double fdummy(std::function<double(const Vector<double> &)> f, const Vector<double> &x, const Vector<double> &d, const double u);


inline LineSearchMethod::LineSearchMethod() {};

inline LineSearchMethod::~LineSearchMethod() {};


//========================================================================
//========================================================================
//
// NAME: std::tuple<int,
//                  Vector<double>,
//                  double> LineSearchMethod::line_minimize(std::function<double(const Vector<double> &)> f,
//                                                          Vector<double> vx1,
//                                                          Vector<double> vx2)
//
// DESC: Minimizes the function f() along the direction (line) vx1 --> xv2.
//
// INPUT:
//     std::function<double(const Vector<double> &)> f :
//     Vector<double> vx1 :
//     Vector<double> vx1 :
//
// OUTPUT:
//     int info :
//     Vector<double> vxmin :
//     double fmin :
//
//========================================================================
//========================================================================
inline std::tuple<
                  int,
                  Vector<double>,
                  double
                  > LineSearchMethod::line_minimize(
                                                          std::function<double(const Vector<double> &)> f,
                                                          const Vector<double> &x,
                                                          const Vector<double> &d
                                                          )
{
    int info;
    Vector<double> xmin;
    double fmin;
    
    std::function<double(const double)> fwrap = std::bind(fdummy, std::ref(f), std::cref(x), std::cref(d), std::placeholders::_1);
    
    Brent brent;
    
    double umin;
    std::tie(info, umin, fmin) = brent.minimize(fwrap, 0.0, 1.0);
    
    xmin = (1.0 - umin)*x + d;
    
    return std::make_tuple(info, xmin, fmin);
}

// dummy wrapper routine
static double fdummy(std::function<double(const Vector<double> &)> f, const Vector<double> &x, const Vector<double> &d, const double u)
{
    Vector<double> xp = (1.0 - u)*x + d;
    
    return f(xp);
}